/////////////////////////////////////////////////////////////////////////////
// Name:        toolbarcust.cpp
// Purpose:     Classes for allowing the user to customise toolbars.
// Author:      Julian Smart
// Modified by:
// Created:     2006-11-28
// RCS-ID:      $Id: toolbarcust.cpp,v 1.2 2007/12/21 08:40:49 anthemion Exp $
// Copyright:   (c) Julian Smart
// Licence:     New BSD License
/////////////////////////////////////////////////////////////////////////////

#include "wx/wx.h"

#include "wx/module.h"
#include "toolbarcust/toolbarcust.h"

/*!
 * wxToolBarCustomisationInfoItem stores customisation information about a single tool.
 */

wxToolBarCustomisationInfoItem::wxToolBarCustomisationInfoItem()
{
    m_id = 0;

    m_kind = wxITEM_NORMAL;

    m_enabled = true;
    m_toolStyle = wxTOOL_STYLE_BUTTON;
}

wxToolBarCustomisationInfoItem::wxToolBarCustomisationInfoItem(const wxToolBarCustomisationInfoItem& item)
{
    Copy(item);
}

wxToolBarCustomisationInfoItem::~wxToolBarCustomisationInfoItem()
{
}

void wxToolBarCustomisationInfoItem::Copy(const wxToolBarCustomisationInfoItem& item)
{
    m_toolStyle = item.m_toolStyle;
    m_id = item.m_id;
    m_kind = item.m_kind;

    m_enabled = item.m_enabled;

    m_bmpNormal = item.m_bmpNormal;
    m_bmpDisabled = item.m_bmpDisabled;

    m_label = item.m_label;
    m_name = item.m_name;

    m_shortHelpString = item.m_shortHelpString;
    m_longHelpString = item.m_longHelpString;
}

/*!
 * wxToolBarCustomisationInfo stores customisation information about a single toolbar.
 */

wxToolBarCustomisationInfo::wxToolBarCustomisationInfo(const wxString& toolbarName)
{
    Init();

    m_name = toolbarName;
}

wxToolBarCustomisationInfo::wxToolBarCustomisationInfo(const wxToolBarCustomisationInfo& info)
{
    Init();

    Copy(info);
}

wxToolBarCustomisationInfo::~wxToolBarCustomisationInfo()
{
    Clear();
}

/// Initialises the class
void wxToolBarCustomisationInfo::Init()
{
    m_currentTool = -1;
    m_needsSeparator = false;
    m_toolbarEnabled = true;
    m_createdCount = 0;
    m_currentToolBar = NULL;
    m_canHaveLabels = false;
    m_useLabels = false;

}

/// Clears the items
void wxToolBarCustomisationInfo::Clear()
{
    wxObjectList::compatibility_iterator node = m_toolbarItems.GetFirst();
    while (node)
    {
        wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) node->GetData();
        delete item;
        node = node->GetNext();
    }
    m_toolbarItems.Clear();    
}

/// Copies the object
void wxToolBarCustomisationInfo::Copy(const wxToolBarCustomisationInfo& info)
{
    Clear();

    m_toolbarEnabled = info.m_toolbarEnabled;
    m_canHaveLabels = info.m_canHaveLabels;
    m_useLabels = info.m_useLabels;
    m_name = info.m_name;

    wxObjectList::compatibility_iterator node = info.m_toolbarItems.GetFirst();
    while (node)
    {
        wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) node->GetData();
        m_toolbarItems.Append(new wxToolBarCustomisationInfoItem(*item));
        node = node->GetNext();
    }
}

/// Adds a tool
wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::AddTool(int toolid, const wxString& name,
                const wxString& label,
                const wxBitmap& bitmap,
                const wxBitmap& bmpDisabled,
                wxItemKind kind,
                const wxString& shortHelp,
                const wxString& longHelp,
                int style)
{
    wxToolBarCustomisationInfoItem* item = new wxToolBarCustomisationInfoItem;
    item->m_id = toolid;
    item->m_name = name;
    item->m_label = label;
    item->m_kind = kind;
    item->m_bmpNormal = bitmap;
    item->m_bmpDisabled = bmpDisabled;
    item->m_shortHelpString = shortHelp;
    item->m_longHelpString = longHelp;
    item->m_toolStyle = style;

    if (item->m_shortHelpString.IsEmpty())
        item->m_shortHelpString = wxGetTranslation(item->m_name);
    
    m_toolbarItems.Append(item);
    return * item;
}

/// Adds a normal button tool
wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::AddButton(int toolid, const wxString& name,
                const wxString& label,
                const wxBitmap& bitmap,
                const wxString& shortHelp,
                const wxString& longHelp)
{
    return AddTool(toolid, name, label, bitmap, wxNullBitmap, wxITEM_NORMAL, shortHelp, longHelp);
}

/// Adds a check button tool
wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::AddCheckButton(int toolid, const wxString& name,
                const wxString& label,
                const wxBitmap& bitmap,
                const wxString& shortHelp,
                const wxString& longHelp)
{
    return AddTool(toolid, name, label, bitmap, wxNullBitmap, wxITEM_CHECK, shortHelp, longHelp);
}

/// Adds a radio button tool
wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::AddRadioButton(int toolid, const wxString& name,
                const wxString& label,
                const wxBitmap& bitmap,
                const wxString& shortHelp,
                const wxString& longHelp)
{
    return AddTool(toolid, name, label, bitmap, wxNullBitmap, wxITEM_RADIO, shortHelp, longHelp);
}

/// Adds a control
wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::AddControl(int toolid, const wxString& name,
                const wxString& shortHelp,
                const wxString& longHelp)
{
    return AddTool(toolid, name, wxEmptyString, wxNullBitmap, wxNullBitmap, wxITEM_NORMAL, shortHelp, longHelp,
        wxTOOL_STYLE_CONTROL);
}

/// Adds a separator
wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::AddSeparator()
{
    return AddTool(wxID_SEPARATOR, wxEmptyString, wxEmptyString, wxNullBitmap, wxNullBitmap, wxITEM_NORMAL,
        wxEmptyString, wxEmptyString, wxTOOL_STYLE_SEPARATOR);
}

/// Returns the key with "prefix/" prepended if non-empty
wxString wxToolBarCustomisationInfo::GetKey(const wxString& prefix, const wxString& key) const
{
    wxString k(prefix);
    if (!k.IsEmpty())
        k += wxT("/");
    k += key;
    return k;
}

/// Saves enabled status to config
bool wxToolBarCustomisationInfo::Save(const wxString& path, wxConfigBase& config)
{
    config.Write(GetKey(path, wxT("Enabled")), IsToolBarEnabled());
    config.Write(GetKey(path, wxT("UsingLabels")), GetUseLabels());

    wxObjectList::compatibility_iterator node = m_toolbarItems.GetFirst();
    while (node)
    {
        wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) node->GetData();

        if (!item->IsSeparator())
        {
            config.Write(GetKey(path, item->GetName() + wxT(" Enabled")), item->IsEnabled());
        }
        
        node = node->GetNext();
    }

    return true;
}

/// Load enabled status from config
bool wxToolBarCustomisationInfo::Load(const wxString& path, wxConfigBase& config)
{
    bool val = IsToolBarEnabled();
    if (config.Read(GetKey(path, wxT("Enabled")), & val))
        SetToolBarEnabled(val);

    val = GetUseLabels();
    if (config.Read(GetKey(path, wxT("UsingLabels")), & val))
        SetUseLabels(val);

    wxObjectList::compatibility_iterator node = m_toolbarItems.GetFirst();
    while (node)
    {
        wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) node->GetData();
        if (!item->IsSeparator())
        {
            bool val = item->IsEnabled();
            if (config.Read(GetKey(path, item->GetName() + wxT(" Enabled")), & val))
                item->Enable(val);
        }

        node = node->GetNext();
    }
    return true;
}

/// Reset to beginning of info, to be called before iterating
bool wxToolBarCustomisationInfo::Reset(wxToolBarBase* toolBar)
{
    m_currentTool = -1;
    m_needsSeparator = false;
    m_createdCount = 0;
    m_currentToolBar = toolBar;
    return true;
}

/// Call at the beginning of the loop
bool wxToolBarCustomisationInfo::GetNextItem()
{
    m_currentTool ++;
    while (m_currentTool < GetTotalItemCount() && (IsSeparator() || !IsEnabled()))
    {
        if (IsSeparator())
            m_needsSeparator = true;
        m_currentTool ++;
    }
    return (m_currentTool < GetTotalItemCount());
}

/// Creates a tool using the current info. Also implicitly creates a separator
/// if appropriate.
bool wxToolBarCustomisationInfo::CreateTool()
{
    if (!m_currentToolBar)
        return false;
    
    if (m_needsSeparator && m_createdCount > 0)
    {
        m_currentToolBar->AddSeparator();
    }
    
    m_needsSeparator = false;
    m_createdCount ++;

    const wxToolBarCustomisationInfoItem& item = GetCurrentItem();
    
    return NULL != m_currentToolBar->AddTool(item.GetId(), item.GetLabel(),
        item.GetNormalBitmap(), item.GetDisabledBitmap(), item.GetKind(),
        item.GetShortHelp(), item.GetLongHelp());
}

/// Creates a tool using the current info. Also implicitly creates a separator
/// if appropriate.
bool wxToolBarCustomisationInfo::CreateTool(wxControl* control)
{
    if (!m_currentToolBar)
        return false;
    
    if (m_needsSeparator && m_createdCount > 0)
    {
        m_currentToolBar->AddSeparator();
    }

    m_needsSeparator = false;
    m_createdCount ++;
    
    return NULL != m_currentToolBar->AddControl(control);
}

/// True if the current tool is a control
bool wxToolBarCustomisationInfo::IsControl() const
{
    return GetCurrentItem().IsControl();
}

/// True if the current tool is a button
bool wxToolBarCustomisationInfo::IsButton() const
{
    return GetCurrentItem().IsButton();
}

/// True if the current tool is a separator
bool wxToolBarCustomisationInfo::IsSeparator() const
{
    return GetCurrentItem().IsSeparator();
}

/// True if the current tool is enabled
bool wxToolBarCustomisationInfo::IsEnabled() const
{
    const wxToolBarCustomisationInfoItem& item = GetCurrentItem();
    return item.IsEnabled();
}

/// Get total number of items
int wxToolBarCustomisationInfo::GetTotalItemCount() const
{
    return m_toolbarItems.GetCount();
}

/// Get number of enabled items
int wxToolBarCustomisationInfo::GetEnabledItemCount() const
{
    int i;
    int count = 0;
    for (i = 0; i < GetTotalItemCount(); i++)
    {
        const wxToolBarCustomisationInfoItem& item = GetItem(i);
        if (item.IsEnabled())
            count ++;
    }
    return count;
}

/// Gets the nth item
const wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::GetItem(int n) const
{
    wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) m_toolbarItems.Item(n)->GetData();
    return *item;
}

wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::GetItem(int n)
{
    wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) m_toolbarItems.Item(n)->GetData();
    return *item;
}

/// Gets the current item
const wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::GetCurrentItem() const
{
    const wxToolBarCustomisationInfoItem& item = GetItem(m_currentTool);
    return item;
}

wxToolBarCustomisationInfoItem& wxToolBarCustomisationInfo::GetCurrentItem()
{
    wxToolBarCustomisationInfoItem& item = GetItem(m_currentTool);
    return item;
}

/// Finds a tool by name
wxToolBarCustomisationInfoItem* wxToolBarCustomisationInfo::Find(const wxString& name) const
{
    int i;
    for (i = 0; i < GetTotalItemCount(); i++)
    {
        wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) m_toolbarItems.Item(i)->GetData();
        if (item->GetName() == name)
            return item;
    }
    return NULL;
}

/// Finds a tool by id
wxToolBarCustomisationInfoItem* wxToolBarCustomisationInfo::Find(int id) const
{
    int i;
    for (i = 0; i < GetTotalItemCount(); i++)
    {
        wxToolBarCustomisationInfoItem* item = (wxToolBarCustomisationInfoItem*) m_toolbarItems.Item(i)->GetData();
        if (item->GetId() == id)
            return item;
    }
    return NULL;
}

/*!
 * wxToolBarCustomisationManager manages multiple customisation information.
 */

wxToolBarCustomisationManager::wxToolBarCustomisationManager()
{
}

wxToolBarCustomisationManager::~wxToolBarCustomisationManager()
{
    Clear();
}

/// Initialises the class
void wxToolBarCustomisationManager::Init()
{
}

/// Clears the items
void wxToolBarCustomisationManager::Clear()
{
    wxObjectList::compatibility_iterator node = m_infos.GetFirst();
    while (node)
    {
        wxToolBarCustomisationInfo* item = (wxToolBarCustomisationInfo*) node->GetData();
        delete item;
        node = node->GetNext();
    }
    m_infos.Clear();    
}

/// Adds information about a toolbar
void wxToolBarCustomisationManager::Add(wxToolBarCustomisationInfo* info)
{
    m_infos.Append(info);
}

/// Finds information about a toolbar
wxToolBarCustomisationInfo* wxToolBarCustomisationManager::Find(const wxString& name) const
{
    int i;
    for (i = 0; i < GetCount(); i++)
    {
        wxToolBarCustomisationInfo* item = (wxToolBarCustomisationInfo*) m_infos.Item(i)->GetData();
        if (item->GetName() == name)
            return item;
    }
    return NULL;
}

/// Finds the nth info for the given name
int wxToolBarCustomisationManager::FindIndex(const wxString& name) const
{
    int i;
    for (i = 0; i < GetCount(); i++)
    {
        wxToolBarCustomisationInfo* item = (wxToolBarCustomisationInfo*) m_infos.Item(i)->GetData();
        if (item->GetName() == name)
            return i;
    }
    return -1;
}


/// Gets the nth record
wxToolBarCustomisationInfo* wxToolBarCustomisationManager::GetNth(int n) const
{
    wxToolBarCustomisationInfo* item = (wxToolBarCustomisationInfo*) m_infos.Item(n)->GetData();
    return item;
}

/// Saves enabled status to config
bool wxToolBarCustomisationManager::Save(const wxString& path, wxConfigBase& config)
{
    int i;
    for (i = 0; i < GetCount(); i++)
    {
        wxToolBarCustomisationInfo* item = (wxToolBarCustomisationInfo*) m_infos.Item(i)->GetData();
        wxString thisPath = path;
        if (!thisPath.IsEmpty())
            thisPath += wxT("/");
        thisPath += item->GetName();

        item->Save(thisPath, config);
    }
    return true;
}

/// Load enabled status from config
bool wxToolBarCustomisationManager::Load(const wxString& path, wxConfigBase& config)
{
    int i;
    for (i = 0; i < GetCount(); i++)
    {
        wxToolBarCustomisationInfo* item = (wxToolBarCustomisationInfo*) m_infos.Item(i)->GetData();
        wxString thisPath = path;
        if (!thisPath.IsEmpty())
            thisPath += wxT("/");
        thisPath += item->GetName();

        item->Load(thisPath, config);
    }
    return true;
}

/*!
 * A toolbar that sends an event to itself when requesting customisation
 */

#define wxID_CUSTOMIZE_TOOLBAR  wxID_HIGHEST + 1

IMPLEMENT_CLASS(wxCustomisableToolBar, wxToolBar)

BEGIN_EVENT_TABLE(wxCustomisableToolBar, wxToolBar)
    EVT_RIGHT_DOWN(wxCustomisableToolBar::OnRightDown)
END_EVENT_TABLE()

wxMenu*  wxCustomisableToolBar::sm_menu = NULL;
long     wxCustomisableToolBar::sm_commandId = -1;

wxCustomisableToolBar::wxCustomisableToolBar(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& sz, long style)
{
    Init();
    Create(parent, id, pos, sz, style);

#if 0 // def __WXMSW__
    int majorVersion, minorVersion;
    wxGetOsVersion(& majorVersion, & minorVersion);
    if (majorVersion >= 6)
    {
        SetBackgroundColour(GetBackgroundColour());
    }
#endif

}

wxCustomisableToolBar::~wxCustomisableToolBar()
{
    if (sm_menu)
        sm_menu->SetInvokingWindow(NULL);
    Disconnect(sm_commandId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxCustomisableToolBar::OnCustomise));
}

bool wxCustomisableToolBar::Create(wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& sz, long style)
{
    wxToolBar::Create(parent, id, pos, sz, style);

    return true;
}

void wxCustomisableToolBar::Init()
{
    // m_menu = NULL;
    m_expandToFitParent = false;

    if (sm_commandId == -1)
        sm_commandId = wxNewId();

    Connect(sm_commandId, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(wxCustomisableToolBar::OnCustomise));
}

void wxCustomisableToolBar::OnCustomise(wxCommandEvent& WXUNUSED(event))
{
    wxCommandEvent cmdEvent(wxEVT_COMMAND_MENU_SELECTED, wxID_CUSTOMIZE_TOOLBAR);
    cmdEvent.SetString(m_customisationName);

    GetEventHandler()->ProcessEvent(cmdEvent);
}

void wxCustomisableToolBar::OnRightDown(wxMouseEvent& WXUNUSED(event))
{
    if (!m_customisationName.IsEmpty())
    {
        if (!sm_menu)
        {
            sm_menu = new wxMenu;
            sm_menu->Append(sm_commandId, _("Customise..."));
        }

        wxPoint pt = wxGetMousePosition();
        wxPoint ptClient = ScreenToClient(pt);
        PopupMenu(sm_menu, ptClient);        
    }
}

void wxCustomisableToolBar::DoSetSize(int x, int y,
                           int width, int height,
                           int sizeFlags)
{
    if (m_expandToFitParent)
    {
        wxWindow* parent = GetParent();
        wxSize sz = parent->GetClientSize();
        
        if (width != -1)
            width = sz.x;
    }

    wxToolBar::DoSetSize(x, y, width, height, sizeFlags);
}

void wxCustomisableToolBar::OnInternalIdle()
{
    wxToolBar::OnInternalIdle();
}

void wxCustomisableToolBar::CleanUpMenu()
{
    delete sm_menu;
    sm_menu = NULL;
}

// A module to clean up the custom toolbar menu

class wxCustomisableToolBarModule: public wxModule
{
DECLARE_DYNAMIC_CLASS(wxCustomisableToolBarModule)
public:
    wxCustomisableToolBarModule() {}
    bool OnInit() { return true; };
    void OnExit() { wxCustomisableToolBar::CleanUpMenu(); }
};

IMPLEMENT_DYNAMIC_CLASS(wxCustomisableToolBarModule, wxModule)

